Julia es un lenguaje de alto nivel que permite escribir código de manera fácil y rápida, pero con una velocidad de ejecución similar a la de C (~ 2x)
In [1]:
superior = 1
Out[1]:
In [2]:
inferior = superior - 1
Out[2]:
In [3]:
λ = 0.05 # Unicode characters are allowed as names: \lambda<tab>
inferior <= λ <= superior
Out[3]:
Julia posee varios built-in types
(DataType
s), como Float64
que representa a un número de coma flotante de 64 bits. Pero lo interesante es que los types
creados por los usuarios son tan rápidos como los built-in.
In [4]:
typeof(λ)
Out[4]:
In [5]:
λ::Float64 # Type assertion
Out[5]:
In [6]:
λ::Int # Type assertion
De hecho, Julia es un lenguaje homoiconico, por lo que su biblioteca base está escrita en Julia.
La definición de Float64
en Julia es:
abstract Number
abstract Real <: Number
abstract AbstractFloat <: Real
bitstype 32 Float32 <: AbstractFloat
bitstype 64 Float64 <: AbstractFloat
In [7]:
super(Float64)
Out[7]:
In [8]:
subtypes(AbstractFloat)
Out[8]:
Para Julia es posible elegir el método más específico para cada combinación de tipos de argumentos, debido a su diseño basado en multiple dispatch. Uno puede preguntar por el método que se ejecutó usando el macro @which
In [9]:
@which λ * 100::Int
Out[9]:
In [10]:
@which λ * Float64(100)
Out[10]:
Julia es JIT (just-in-time) compiled, por lo que la primera vez que se llama a una función, su tiempo de ejecución es más lento (porque es compilada) pero la segunda vez es casi tan rápida como si corriera en C (dado que fue compilada específicamente para el tipo de datos de sus argumentos)
In [11]:
@time λ * 100
Out[11]:
In [12]:
@time λ * 100
Out[12]:
In [13]:
lista = [1, λ, π, "Hola mundo"]
Out[13]:
In [14]:
typeof(lista)
Out[14]:
Si un array contiene siempre un mismo tipo de datos, su almacenamiento en memoria es más eficiente si lo declaramos. A su vez las funciones que lo utilizan se ejecutarán de manera más eficiente/rápida (porque el compilador puede predecir el tipo de datos que va a obtener de array).
In [15]:
identidad = Float64[62, 95, 99, 30]
Out[15]:
In [16]:
identidad[1] # Los Arrays se acceden desde 1
Out[16]:
In [17]:
identidad[2:3] # Es posible acceder usando rangos start:end
Out[17]:
In [18]:
identidad[end] = 100 # Es posible asignar un elemento a un índice en particular, "end" permite obtener el último ítem
identidad
Out[18]:
Es posible indexar un array usando otro array, por ejemplo usando arrays lógicos
In [19]:
usar = identidad .> 95.0 # .> compara el array elemento a elemento
Out[19]:
In [20]:
identidad[ usar ]
Out[20]:
Existen varias dequeue functions en Julia. Dado que modifican el array que reciben, por convención sus nombres terminan en !
, por ejemplo:
push! # Al final del array
pop!
shift! # Al inicio del array
unshift!
splice! # Toma un valor dentro del array
In [21]:
push!(identidad, 30)
identidad
Out[21]:
In [24]:
matrix = [ 0.5 0.6
0.7 0.8 ]
Out[24]:
In [25]:
matrix[2,1] # Fila 2, Columna 1
Out[25]:
In [26]:
matrix[3] # La matriz se almacena de manera continua en memoria; column-major order.
Out[26]:
In [32]:
map = Dict('A'=>1, 'B'=>2, 'C'=>3)
Out[32]:
In [33]:
map['D'] = 4 # Agrega un nuevo par (Pair) llave => valor al diccionario
Out[33]:
In [34]:
map['A'] = 5 # Si la llave ya existe, el valor es reemplazado
map
Out[34]:
In [35]:
map['B']
Out[35]:
In [36]:
map['E'] # Error: 'E' no está en map
In [37]:
get(map, 'E', 0) # Es posible usar get para definir un valor default que evite el error
Out[37]:
In [38]:
identidad = rand() * 100.0
Out[38]:
In [39]:
if identidad == 100.0
println("Idénticas")
elseif identidad >= 30 # Opcional
println("Homólogas")
else # Opcional
println("Twilight")
end
In [40]:
numero = rand(1:100)
Out[40]:
In [41]:
if numero % 2 == 0
es_par = "si"
else
es_par = "no"
end
es_par
Out[41]:
In [42]:
es_par = numero % 2 == 0 ? "si" : "no"
Out[42]:
In [43]:
numero = 0
limite = 3
while numero < limite
numero += 1
println(numero)
end
In [44]:
carpeta = "data"
archivos = readdir(carpeta)
Out[44]:
In [45]:
for nombre in archivos # for arch = archivos
println(nombre)
end
En Julia los for
s son reescritos como while
s, usando las funciones start
para inicializar la iteración, done
para testear si se alcanzó el final de la iteración y next
para obtener el valor de la iteración y el del próximo estado. Uno puede definir estas funciones para cualquier tipo propio que quiera hacer iterable.
In [46]:
state = start(archivos) # state = 1
while !done(archivos, state) # !( state > length(archivos) )
(nombre, state) = next(archivos, state) # archivos[state], state + 1
println(nombre)
end
In [47]:
for nombre in archivos
println( joinpath(carpeta, nombre) )
end
In [48]:
len = length(archivos)
lista = Array(Int, len)
for i in 1:len
lista[i] = filesize(joinpath(carpeta, archivos[i])) # Tamaño en bytes
end
lista
Out[48]:
In [49]:
lista = [ filesize(joinpath(carpeta, nombre)) for nombre in archivos ]
Out[49]:
Los strings son secuencias finitas de caracteres. En sus principios la bioinformática se trató del análisis de secuencias de caracteres (utilizando la codificación ASCII de 8 bits), lo que hizo popular a Perl en el área. Julia tiene un buen soporte para strings:
In [50]:
cadena_unicode = "∃x ∈ B ∧ x ∈ A"
Out[50]:
In [51]:
typeof(cadena_unicode)
Out[51]:
In [52]:
cadena_ascii = "A es un subconjunto de B"
Out[52]:
In [53]:
typeof(cadena_ascii)
Out[53]:
Es seguro iterar sobre un string (inmutable) para obtener sus caracteres. Si se quiere obtener un Vector{Char}
(Array
de una dimensión, mutable) se puede usar list comprehension o la función collect
.
In [54]:
for char in cadena_ascii
print(char)
end
In [55]:
for char in cadena_unicode
print(char)
end
In [56]:
collect(cadena_unicode) # [ char for char in cadena_unicode ]
Out[56]:
Sin embargo, acceder directamente a un string como si fuera un array no es una acción segura dado que un carácter puede estar codificado por más de un valor de 8 bits. Sólo es seguro hacer eso para ASCIIString
s, dado que cada carácter está codificado por un sólo número entero de 8 bits. Pero no es seguro hacerlo para otras codificación. Por ejemplo, la codificación UTF-8 de ∃ (\exists<tab>
en la consola) requiere de tres valores de 8 bits:
In [57]:
for i in 1:4
println(i, " ", cadena_ascii[i])
end
In [58]:
for i in 1:4
try
println(i, " ", cadena_unicode[i])
catch err
println(i, " ", err) # Error al acceder cadena_unicode[i]
end
end
In [59]:
ext_fasta = r"\.fasta$" # r"... permite escribir una expresión regular
Out[59]:
In [60]:
typeof(ext_fasta)
Out[60]:
In [61]:
for nombre in archivos
println(nombre, "\t:\t", ismatch(ext_fasta, nombre)) # ismatch es true si la regex está en el string
end
In [62]:
ismatch(r"^>\w{4}\.\w", ">2trx.A")
Out[62]:
In [63]:
ismatch(r"^∃x\s+", cadena_unicode) # UNICODE UTF-8
Out[63]:
In [64]:
captura = match(r"^>(\w{4})\.(\w)", ">2trx.A")
Out[64]:
In [65]:
if captura != nothing
println("PDB\t", captura[1]) # captura[1] == captura.captures[1]
println("Cadena\t", captura[2])
else
println("No es un PDB ID")
end
In [66]:
captura = match(r"^>(\w{4})\.(\w)", ">PF00085") # nothing no imprime nada en pantalla
In [67]:
if captura != nothing
println("PDB\t", captura[1])
println("Cadena\t", captura[2])
else
println("No es un PDB ID")
end
In [69]:
A, B = rand(1:6), rand(1:6)
"Su dado es $A, mientras el dado de IJulia es $B: $( A > B ? "usted gana" : A != B ? "IJulia gana" : "empate")"
Out[69]:
In [70]:
stream = open("data/PF09645_full.fasta", "r")
Out[70]:
In [71]:
for line in eachline(stream) # Itero para cada línea (incluye '\n')
print(line)
end
In [72]:
close(stream)
open( … ) do … asegura que el archivo se cierre si ocurre algún error (implementa un try/catch)
In [73]:
open("data/PF09645_full.fasta", "r") do stream
for line in eachline(stream)
print(line)
end
end
In [74]:
function listaralineamientos(direccion, extension::Regex=r"\.fasta$"; vacios::Bool=false)
alns = ASCIIString[]
for nombre in readdir(direccion)
if ismatch(extension, nombre)
if vacios || filesize(joinpath(direccion, nombre)) >0
push!(alns, nombre)
end
end
end
alns
end
Out[74]:
In [75]:
listaralineamientos("data")
Out[75]:
In [76]:
listaralineamientos("data", vacios=true)
Out[76]:
In [77]:
methods(listaralineamientos)
Out[77]:
In [78]:
listaralineamientos("data", r"\.stockholm$")
Out[78]:
In [79]:
listarstockholm(carpeta) = listaralineamientos(carpeta, r"\.stockholm$")
Out[79]:
In [80]:
listarstockholm("data")
Out[80]: